原文在这里. 有段时间不看了, 有些忘了,有些地方还有一定的加深.
什么是 React stateless function?
es6的语法
1 | class List extends React.Component { |
简单的 javascripg函数也可以!
1 | //Stateless function syntax |
彻底的模板,没有自己任何的数据,也没有生命周期方法. 纯粹依赖于输入.
首先来定义一个 App Container
目的是最为一个函数接收 app sate 对象
1 | import React from 'react'; |
在纯函数中,state 必须要在外部管理,然后以 props 的形式传递给组件
.
下面看看这个解释的例子
Stateless Timer component
简单的 timer 组件只接受 secondsElapsed 参数:
1 | import React from 'react'; |
添加到 APP 中
1 | import React from 'react'; |
最后创建main.js 文件,启动渲染过程
1 | import App from './components/app'; //导入容器组件 |
对于上面的代码, 变化的是组件的 state, 渲染的目标元素是一直不变的, 所以我们用柯理化配置好一个工厂函数
1 | //闭包再工作! |
柯理化返回的函数,等待传入 props
1 | (props) => ReactDOM.render(...) |
只要 State发生变化,我们需要渲染时,只需要传递 state 就可以了
1 | setInterval(() => { |
每一秒钟, secondsElapsed 属性会递增1, 然后作为参数传递给 render 函数
现在可以实现 Redux 风格的 reduce 函数, reduce式的函数不能突变当前值
1 | currentState->newState |
使用 Radma 的 Lenses 来实现
1 | const secondsElapsedLens = R.lensProp('secondsElapsed'); |
首先创建 Lens
:
1 | const secondsElapsedLens = R.lensProp('secondsElapsed'); |
lens可以聚焦于给定的属性,不会针对特定的对象, 所以可以重用.
View
1 | R.view(secondsElapsedLens, { secondsElapsed: 10 }); //=> 10 |
Set
1 | R.set(secondsElapsedLens, 11, { secondsElapsed: 10 }); //=> 11 |
用给定的函数 Set
1 | R.over(secondsElapsedLens, R.inc, { secondsElapsed: 10 }); //=> 11 |
inSecondElapsed reducer 是一个偏应用函数(partial application),
这一行
1 | const incSecondsElapsed = R.over(secondsElapsedLens, R.inc); |
会返回一个新的函数,一旦用appState 调用, 就会应用 R.inc在 lensed prop secondElapsed 上.
1 | appState=incSecondElapsed(appState) |
组合 React stateless components
开篇提到,React 组件可以作为函数, 那么可以用 R.compose来 compose 这些函数吗?
当然是可以的
用 React.createClass 是这样的:
1 | const TodoList = React.createClass({ |
现在问题是: TodoList 可以由小的可重用部分 composition 而成吗? 可以的. 可以分为三个更小的组件
- 容器组件
1 | const Container = children => (<div className="panel panel-default"> |
- 列表组件
1 | const List = children => (<ul> |
- 列表项组件
1 | const ListItem = ({ id, text }) => (<li key={id}> |
现在一步一动,看看每一步的输出
1 | Container(<h1>Hello World!</h1>); |
- mapTodos 可以有更简单的模式
1 | //This |
- const mapTodos = R.map(ListItem); Ramda 函数式自动柯理化的,所以代码是这样的, 等待传递数据数组,返回的数组的形式是
- {data.item} 组成的数组
完整的 TodoList 的代码就是
1 | import React from 'React'; |
工厂配置好了,就等数据了
- 模拟一下 appState 的 todo 数据
1 | let appState = { |
- 在 App 组件中添加 TodoList 组件作为子组件
1 | import TodoList from './todo-list'; |
TodoList组件期待的参数是一个todos数组,
1 | <TodoList todos={appState.todos} /> |
React stateless component是作为函数的,所以我们也可以传递参数
1 | TodoList({todos: appState.todos}); |
最好是传递单个参数,所以这种情况,再改进一下
1 | const TodoList = R.compose(Container, List, R.map(ListItem), R.prop('todos')); |
调用就直接改为:
1 | TodoList(appState) |
结束